#pragma once 
#include <cinttypes>
#include <iostream>
#include "Log.hpp"
#include "Thread.hpp"
#include "Cond.hpp"
#include "Mutex.hpp"
#include <pthread.h>
#include <vector>
#include <queue>

namespace ThreadPoolModule {
    using namespace ThreadModule;
    using namespace LogModule;
    using namespace CondModule;
    using namespace MutexModule;

    static const int N = 5;
    template<class T>
    class ThreadPool {
        private:
            void WakeUpAllThread() {
                LockGuard lock(_mutex);
                if(_sleepernum) {
                    _cond.Broadcast();
                }
                LOG(LogLevel::INFO) << "唤醒了所有的休眠线程";
            }
            void WakeUpOne() {
                _cond.Signal();
                LOG(LogLevel::INFO) << "唤醒了一个休眠的线程";
            }
            ThreadPool(int n = N) : _num(n), _isrunning(false), _sleepernum(0) {
                for(int i = 0; i < _num; i++) {
                    _threads.emplace_back([this]() {
                        HandlerTask();
                    });
                }
            }
            void Start() {
                if(_isrunning) {
                    return;
                }
                _isrunning = true;
                for(auto& thread : _threads) {
                    thread.Start();
                    LOG(LogLevel::INFO) << "启动新的线程成功" << thread.Name();
                }
            }
            ThreadPool(const ThreadPool<T>&) = delete;
            ThreadPool<T>& operator=(const ThreadPool<T>&) = delete;
        public:
            static ThreadPool<T>* GetInstance() { // 懒汉模式，常见了之后不再创建了
                if(inc == nullptr) {
                    LockGuard lock(_lock);
                    LOG(LogLevel::DEBUG) << "获取单例中...";
                    if(inc == nullptr) {
                        LOG(LogLevel::DEBUG) << "首次使用单例，创建之...";
                        inc = new ThreadPool<T>();
                        inc->Start();
                    }
                }
                return inc;
            }
            void Stop() {
                if(!_isrunning) {
                    return;
                }
                _isrunning = false;
                WakeUpAllThread();
            }
            void Join() {
                for(auto& thread : _threads) {
                    thread.Join();
                }
            }
            void HandlerTask() {
                char name[128];
                pthread_getname_np(pthread_self(), name, sizeof(name));
                while (1) {
                    T t;
                    {
                        LockGuard lock(_mutex);
                        while(_tq.empty() && _isrunning) {
                            _sleepernum++;
                            _cond.Wait(_mutex);
                            _sleepernum--;
                        }
                        if(!_isrunning && _tq.empty()) {
                            LOG(LogLevel::INFO) << name << "退出了，线程池退出了并且任务处理完成了";
                            break;
                        }
                        // 有任务
                        t = _tq.front();
                        _tq.pop();
                    }
                    t(); // 这个不能放在临界区中，消耗大，占用大
                }
            }
            bool Enqueue(const T& in) {
                if(_isrunning) {
                    LockGuard lock(_mutex);
                    _tq.push(in);
                    if(_threads.size() == _sleepernum) {
                        WakeUpOne();
                    }
                    return true;
                }
                return false;
            }
            ~ThreadPool() {}
        private:
            std::vector<Thread> _threads;
            int _num; 
            std::queue<T> _tq;
            Cond _cond;
            Mutex _mutex;
            bool _isrunning;
            int _sleepernum;
            static ThreadPool<T>* inc; // 单例指针，这里实现的是懒汉模式
            static Mutex _lock;
    };
    template<class T>
    ThreadPool<T>* ThreadPool<T>::inc = nullptr;
    template<class T>
    Mutex ThreadPool<T>::_lock;
}

